/*
 * Copyright (C) 2013 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { TlsVersion } from "./TlsVersion"
import { socket } from '@kit.NetworkKit';

/**
 * A record of a TLS handshake. For HTTPS clients, the client is *local* and the remote server is
 * its *peer*.
 *
 * This value object describes a completed handshake. Use [ConnectionSpec] to set policy for new
 * handshakes.
 */
export class Handshake {

  /**
   * Returns the TLS version used for this connection. This value wasn't tracked prior to OkHttp
   * 3.0. For responses cached by preceding versions this returns [TlsVersion.SSL_3_0].
   */
  #tlsVersion: TlsVersion
  get tlsVersion(): TlsVersion{
    return this.#tlsVersion
  }

  /** Returns the cipher suite used for the connection. */
  #cipherSuite: string // CipherSuite
  get cipherSuite(): string{
    return this.#cipherSuite
  }

  /** Returns a possibly-empty list of certificates that identify this peer. */
  #localCertificates: socket.X509CertRawData
  get localCertificates(): socket.X509CertRawData{
    return this.#localCertificates
  }

  // Delayed provider of peerCertificates, to allow lazy cleaning.
  peerCertificatesFn: () => socket.X509CertRawData
  constructor(tlsVersion: TlsVersion, cipherSuite: string, localCertificates: socket.X509CertRawData, peerCertificatesFn: () => socket.X509CertRawData) {
    this.#tlsVersion = tlsVersion
    this.#cipherSuite = cipherSuite
    this.#localCertificates = localCertificates
    this.peerCertificatesFn = peerCertificatesFn
  }

  /** Returns a possibly-empty list of certificates that identify the remote peer. */
  #peerCertificates: socket.X509CertRawData | null
  get peerCertificates(): socket.X509CertRawData | null{
    try {
      this.#peerCertificates = this.peerCertificatesFn()
    }catch (e) {
      this.#peerCertificates = null
    }
    return this.#peerCertificates
  }

  /** Returns the remote peer's principle, or null if that peer is anonymous. */
  // #peerPrincipal: Principal | null
  // get peerPrincipal(): Principal | null{
  //   return this.#peerCertificates.firstOrNull() as? X509Certificate)?.subjectX500Principal
  // }
  //
  // /** Returns the local principle, or null if this peer is anonymous. */
  // #localPrincipal: Principal | null
  // get localPrincipal(): Principal | null{
  //   return this.#localCertificates.firstOrNull() as? X509Certificate)?.subjectX500Principal
  // }

  equals(other: unknown): boolean {
    return other instanceof  Handshake &&
      other.tlsVersion == this.#tlsVersion &&
      other.cipherSuite == this.#cipherSuite &&
      // other.peerCertificates == this.#peerCertificates &&
      other.localCertificates == this.#localCertificates
  }

  hashCode(): number {
    var result = 17
    // result = 31 * result + tlsVersion.hashCode()
    // result = 31 * result + cipherSuite.hashCode()
    // result = 31 * result + peerCertificates.hashCode()
    // result = 31 * result + localCertificates.hashCode()
    return result
  }

  toString(): string {
    // let peerCertificatesString = peerCertificates.map { it.name }.toString()
    return "Handshake{" +
      "tlsVersion=$tlsVersion " +
      "cipherSuite=$cipherSuite " +
      "peerCertificates=$peerCertificatesString " +
      "localCertificates=${localCertificates.map { it.name }}}"
  }

  // private Certificate.name: String
  // get() = when (this) {
  //   is X509Certificate -> subjectDN.toString()
  //   else -> type
  // }
//
//   companion object {
//     @Throws(IOException::class)
//     @JvmStatic
//     @JvmName("get")
//     fun SSLSession.handshake(): Handshake {
//       val cipherSuiteString = checkNotNull(cipherSuite) { "cipherSuite == null" }
//       val cipherSuite = when (cipherSuiteString) {
//         "TLS_NULL_WITH_NULL_NULL", "SSL_NULL_WITH_NULL_NULL" -> {
//           throw IOException("cipherSuite == $cipherSuiteString")
//         }
//         else -> CipherSuite.forJavaName(cipherSuiteString)
//       }
//
//       val tlsVersionString = checkNotNull(protocol) { "tlsVersion == null" }
//       if ("NONE" == tlsVersionString) throw IOException("tlsVersion == NONE")
//       val tlsVersion = TlsVersion.forJavaName(tlsVersionString)
//
//       val peerCertificatesCopy = try {
//         peerCertificates.toImmutableList()
//       } catch (_: SSLPeerUnverifiedException) {
//         listOf()
//       }
//
//       return Handshake(tlsVersion, cipherSuite,
//       localCertificates.toImmutableList()) { peerCertificatesCopy }
//     }
//
//     private fun Array<out Certificate>?.toImmutableList(): List<Certificate> {
//       return if (this != null) {
//       immutableListOf(*this)
//     } else {
//       emptyList()
//     }
//   }
//
//   @JvmStatic
//   fun get(
//     tlsVersion: TlsVersion,
//   cipherSuite: CipherSuite,
//   peerCertificates: List<Certificate>,
//   localCertificates: List<Certificate>
//   ): Handshake {
//     val peerCertificatesCopy = peerCertificates.toImmutableList()
//     return Handshake(tlsVersion, cipherSuite, localCertificates.toImmutableList()) {
//       peerCertificatesCopy
//     }
//   }
// }
}
